import tkinter as tk
from tkinter import messagebox
from tkinter.filedialog import askdirectory
from tkinter import ttk
import paramiko
import os
import threading

from tqdm import tqdm


class RemoteFileBrowserBase:
    def __init__(self, root, extend_name=None, download_path=None, close_once_done=False, res_callback=None):
        self.root = root
        self.root.title("Remote File Browser")
        self.sftp = None
        self.current_path = "/"
        self.download_thread = None
        self.download_path = download_path
        self.extend_name = extend_name
        self.close_once_done = close_once_done
        self.res_callback = res_callback

        # 设置主题和样式
        self.style = ttk.Style()
        self.style.configure('TButton', font=('Arial', 10, 'bold'), padding=6)
        self.style.configure('TLabel', font=('Arial', 10), background='#f0f0f0')
        self.style.configure('TProgressbar', thickness=25, maximum=100, length=300)

        self._create_connection_widgets()
        self._create_file_list_widgets()
        self._create_progress_widgets()

    def _create_connection_widgets(self):
        """创建和放置服务器连接相关的控件"""
        self.host_label = ttk.Label(self.root, text="Server Address:")
        self.host_label.grid(row=0, column=0, padx=10, pady=5, sticky='w')
        self.host_entry = ttk.Entry(self.root, width=40)
        self.host_entry.grid(row=0, column=1, padx=10, pady=5)

        self.username_label = ttk.Label(self.root, text="Username:")
        self.username_label.grid(row=1, column=0, padx=10, pady=5, sticky='w')
        self.username_entry = ttk.Entry(self.root, width=40)
        self.username_entry.grid(row=1, column=1, padx=10, pady=5)

        self.password_label = ttk.Label(self.root, text="Password:")
        self.password_label.grid(row=2, column=0, padx=10, pady=5, sticky='w')
        self.password_entry = ttk.Entry(self.root, show="*", width=40)
        self.password_entry.grid(row=2, column=1, padx=10, pady=5)

        self.connect_button = ttk.Button(self.root, text="Connect", command=self.connect_to_server)
        self.connect_button.grid(row=3, column=0, columnspan=2, padx=10, pady=15)

    def _create_file_list_widgets(self):
        """创建和放置文件列表及目录导航相关控件"""
        self.path_label = ttk.Label(self.root, text="Current Path: /")
        self.path_label.grid(row=4, column=0, columnspan=2, padx=10, pady=5, sticky='w')

        self.file_listbox = tk.Listbox(self.root, width=50, height=15, font=('Arial', 10))
        self.file_listbox.grid(row=5, column=0, columnspan=2, padx=10, pady=10)
        self.file_listbox.bind("<Double-1>", self.on_item_double_select)

        self.back_button = ttk.Button(self.root, text="Go Back", command=self.go_back)
        self.back_button.grid(row=6, column=0, columnspan=2, padx=10, pady=10)

    def _create_progress_widgets(self):
        """创建并放置下载进度相关控件"""
        self.progress_label = ttk.Label(self.root, text="Download Progress:")
        self.progress_label.grid(row=7, column=0, padx=10, pady=5, sticky='w')

        self.progress_var = tk.DoubleVar()
        self.progress_bar = ttk.Progressbar(self.root, variable=self.progress_var)
        self.progress_bar.grid(row=7, column=1, padx=10, pady=5)

    def connect_to_server(self):
        """连接到远程服务器"""
        host = self.host_entry.get()
        username = self.username_entry.get()
        password = self.password_entry.get()

        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

        try:
            ssh.connect(host, username=username, password=password)
            self.sftp = ssh.open_sftp()
            self.load_directory("/")
        except Exception as e:
            messagebox.showerror("Connection Failed", f"Failed to connect to the server: {e}")

    def load_directory(self, path):
        """加载指定的目录"""
        if not self.sftp:
            messagebox.showerror("Error", "Not connected to the server.")
            return

        try:
            self.current_path = path
            self.path_label.config(text=f"Current Path: {path}")
            items = self.sftp.listdir_attr(path)

            self.file_listbox.delete(0, tk.END)
            for item in items:
                if item.st_mode & 0o40000:  # Check if it's a directory
                    self.file_listbox.insert(tk.END, f"[Folder] {item.filename}")
                    self.file_listbox.itemconfig(tk.END, {"fg": "blue"})
                else:
                    if self.extend_name is None or item.filename.endswith(self.extend_name):
                        self.file_listbox.insert(tk.END, item.filename)
        except Exception as e:
            messagebox.showerror("Error", f"Failed to load directory: {e}")

    def on_item_double_select(self, event):
        """处理文件或文件夹双击选择"""
        if not self.file_listbox.curselection():
            return

        selected_item = self.file_listbox.get(self.file_listbox.curselection())
        if selected_item.startswith("[Folder] "):
            folder_name = selected_item[len("[Folder] "):]
            self.load_directory(f"{self.current_path}/{folder_name}")
        else:
            download = messagebox.askokcancel("File Selected", f"You selected the file: {selected_item}")
            if download:
                download_path = self.download_path if self.download_path else askdirectory(title="Select Directory to Save File")
                local_path = os.path.join(download_path, selected_item)
                self.progress_var.set(0)  # Reset progress bar
                self.download_thread = threading.Thread(target=self._download_file, args=(selected_item, local_path))
                self.download_thread.start()

    def go_back(self):
        """返回父级目录"""
        if self.current_path == "/":
            messagebox.showinfo("Notice", "Already at the root directory.")
            return

        parent_path = "/".join(self.current_path.split("/")[:-1]) or "/"
        self.load_directory(parent_path)

    def _download_file(self, file_name, local_path):
        """下载文件，使用单独的线程进行处理"""
        try:
            remote_file_path = os.path.join(self.current_path, file_name)

            def progress_callback(bytes_transferred, total_size):
                self.progress_var.set((bytes_transferred / total_size) * 100)

            self.sftp.get(remote_file_path, local_path, callback=progress_callback)

            messagebox.showinfo("Download Complete", f"File downloaded successfully to: {local_path}")
            if self.close_once_done:
                self.result = os.path.join(self.download_path, file_name)
                self.res_callback(self.result)
                self.root.destroy()
        except Exception as e:
            messagebox.showerror("Download Failed", f"Failed to download file: {e}")
        finally:
            self.progress_var.set(0)


class RemoteFileBrowserWin(tk.Tk, RemoteFileBrowserBase):
    def __init__(self, extend_name=None, download_path=None):
        tk.Tk.__init__(self)
        RemoteFileBrowserBase.__init__(self, self, extend_name, download_path)


class RemoteFileBrowserDialog(tk.Toplevel, RemoteFileBrowserBase):
    def __init__(self, parent, extend_name=None, download_path=None, res_callback=None):
        tk.Toplevel.__init__(self, parent)
        RemoteFileBrowserBase.__init__(self, self, extend_name, download_path, close_once_done=True, res_callback=res_callback)


if __name__ == "__main__":
    app = RemoteFileBrowserWin(extend_name="bag", download_path="/tmp")
    app.mainloop()
